#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include "pthread.hpp"

#define THREAD_NUM 5
template <class Task>
class threadpool;

template <class Task>
class threadpool
{

    static void *Handle_Func(void *args)
    {
        threadpool<Task> *tp = static_cast<threadpool<Task> *>(args);
        while (1)
        {
            tp->Lock();
            while (tp->isempty())
            {
                tp->cond_wait();
            }
            Task t = tp->_qt.front();
            tp->_qt.pop();
            tp->unLock();
            std::cout << pthread_self() << ":";
            t();
            std::cout << std::endl;
        }
        delete tp;
        return nullptr;
    }

    typedef std::function<void *(void *)> func_t;

public:
    void Lock()
    {
        pthread_mutex_lock(&_mtx);
    }

    void unLock()
    {
        pthread_mutex_unlock(&_mtx);
    }

    void cond_wait()
    {
        pthread_cond_wait(&_cond, &_mtx);
    }

    void cond_signal()
    {
        pthread_cond_signal(&_cond);
    }
    threadpool()
    {
        pthread_mutex_init(&_mtx, 0);
        pthread_cond_init(&_cond, 0);
        for (size_t i = 0; i < THREAD_NUM; i++)
        {
            _threads.push_back(new thread);
        }
    }

    void push(const Task& task)
    {
        Lock();
        _qt.push(task);
        unLock();
        cond_signal();
    }

    void run()
    {
        for (auto &thread : _threads)
        {
            thread->push(Handle_Func, this);
            thread->create();
            thread->detach();
        }
    }

    bool isempty()
    {
        return _qt.empty();
    }

    ~threadpool()
    {
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_cond);
    }

private:
    std::vector<thread *> _threads;
    std::queue<Task> _qt;
    pthread_mutex_t _mtx;
    pthread_cond_t _cond;
};